﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace FileManager.Model
{
    [XmlRoot("FileMetadataCollection")]
    public class FileMetadataCollection : ICollection<MetaData>
    {

        [XmlElement("FileMetadata")]
        private List<MetaData> Items { get; set; } = new List<MetaData>();

        #region ICollection<MetaData> Implementation

        public MetaData this[int index]
        {
            get => Items[index];
            set => Items[index] = value;
        }

        public int Count => Items.Count;

        public bool IsReadOnly => false;

        public void Add(MetaData item)
        {
            Items.Add(item);
        }

        public void Clear()
        {
            Items.Clear();
        }

        public bool Contains(MetaData item)
        {
            return Items.Contains(item);
        }

        public void CopyTo(MetaData[] array, int arrayIndex)
        {
            Items.CopyTo(array, arrayIndex);
        }
        public int IndexOf(MetaData metaData)
        {
            return Items.IndexOf(metaData);
        }
        public IEnumerator<MetaData> GetEnumerator()
        {
            return Items.GetEnumerator();
        }

        public bool Remove(MetaData item)
        {
            return Items.Remove(item);
        }
        public FileMetadataCollection Clone()
        {
            MetaData[] metas = new MetaData[Items.Count];
            Items.CopyTo(metas);
            return new FileMetadataCollection() { Items = metas.ToList() };
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        public static FileMetadataCollection FromEnumerable(IEnumerable<MetaData> source)
        {
            var collection = new FileMetadataCollection();
            if (source != null)
            {
                foreach (var item in source)
                {
                    collection.Items.Add(item);
                }
            }
            return collection;
        }
    }

    public static class FileMetadataUtils
    {
        public static void SaveToFile(FileMetadataCollection collection, string filePath)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(FileMetadataCollection));
            using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                serializer.Serialize(fileStream, collection);
            }
        }

        private static void Ini(string xmlFilePath)
        {
            if(!Path.Exists(xmlFilePath))
            {
                File.Create(xmlFilePath);
            }
        }
        public static FileMetadataCollection LoadFromFile(string filePath)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(FileMetadataCollection));
            using (FileStream fileStream = new FileStream(filePath, FileMode.Open))
            {
                return (FileMetadataCollection)serializer.Deserialize(fileStream);
            }
        }

        public static MetaData? FindByPath(FileMetadataCollection collection, string targetPath)
        {
            return collection.FirstOrDefault(item => item.Path == targetPath);
        }
        public static List<MetaData> FindByTag(FileMetadataCollection collection, string targetTags)
        {
            bool isOnly = targetTags.EndsWith("$");
            if(isOnly)
            {
                targetTags=targetTags.TrimEnd('$');
            }
            targetTags = targetTags.TrimEnd('$');
            string[] tags=targetTags.Split('|');
            if(isOnly)
            {
                return collection.Where(item => item.Tag.Count==tags.Count()&&tags.All(a=>item.Tag.Contains(a))).ToList();
            }
            else
            {
                return collection.Where(item => tags.All(a => item.Tag.Contains(a))).ToList();
            }
        }
        public static void UpdateFileMetadata(string xmlFilePath, MetaData updatedMetadata)
        {
            // 1. 加载XML文件
            var serializer = new XmlSerializer(typeof(FileMetadataCollection));
            FileMetadataCollection collection = null;
            using (var fileStream = new FileStream(xmlFilePath, FileMode.Open, FileAccess.Read))
            {
                collection = (FileMetadataCollection)serializer.Deserialize(fileStream);

                // 2. 查找并更新匹配的元数据
                var matchingItem = collection.FirstOrDefault(item => item.Hash == updatedMetadata.Hash);
                if (matchingItem != null)
                {
                    var index = collection.IndexOf(matchingItem);
                    collection[index] = updatedMetadata;
                }
            }
            if (null != collection)
            {
                // 3. 保存更新后的XML文件
                using (var outputStream = new FileStream(xmlFilePath, FileMode.Truncate, FileAccess.Write))
                {
                    serializer.Serialize(outputStream, collection);
                }
            }
        }

        public static void RemoveFileMetadata(string xmlFilePath, MetaData updatedMetadata)
        {
            // 1. 加载XML文件
            var serializer = new XmlSerializer(typeof(FileMetadataCollection));
            FileMetadataCollection collection = null;
            using (var fileStream = new FileStream(xmlFilePath, FileMode.Open, FileAccess.Read))
            {
                collection = (FileMetadataCollection)serializer.Deserialize(fileStream);

                // 2. 查找并更新匹配的元数据
                var matchingItem = collection.Where(item => item.Hash == updatedMetadata.Hash).ToList();
               
                if (matchingItem != null)
                {
                    matchingItem.ForEach(a=>collection.Remove(a));
                }
            }
            if (null != collection)
            {
                // 3. 保存更新后的XML文件
                using (var outputStream = new FileStream(xmlFilePath, FileMode.Truncate, FileAccess.Write))
                {
                    serializer.Serialize(outputStream, collection);
                }
            }
        }
    }
}
